package ngram_reader.viewer.query;

import math.mathExtended.MathExtended;
import stringFunctions.StringFunctions;
import stringFunctions.Stringify;

/**
 *
 * @author Shimu
 * @date 7-Jul-2013
 */
public class StatisticsSearchQuery extends NoStatSearchQuery {

    public static enum Range {

        /** Any year */
        ALL("All"),
        /** Between two years */
        BETWEEN("Between"),
        /** Greater than a given year */
        GREATER_THAN("Greater than"),
        /** Less than a given year */
        LESS_THAN("Less than");
        private final String DISPLAY_NAME;

        private Range(String displayName) {
            this.DISPLAY_NAME = displayName;
        }

        @Override
        public String toString() {
            return DISPLAY_NAME;
        }
    }

    public static enum Aggregate {

        EACH_YEAR("Each Year"),
        ALL("Total");
        private final String DISPLAY_NAME;

        private Aggregate(String displayName) {
            this.DISPLAY_NAME = displayName;
        }

        @Override
        public String toString() {
            return DISPLAY_NAME;
        }
    }
    private String query;
    private final int startYear, endYear,
            startMatch, endMatch, startVolume, endVolume;
    private final Accumulator yearMatchVolumeAc;

    protected StatisticsSearchQuery(String query, Match match,
            int startGram, int endGram, boolean matchCase,
            int startYear, int endYear, int startMatch, int endMatch,
            int startVolume, int endVolume,
            Aggregate aggregateMatch, Aggregate aggregateVolume) {
        super(query, match, startGram, endGram, matchCase);

        this.startYear = startYear;
        this.endYear = endYear;
        this.startMatch = startMatch;
        this.endMatch = endMatch;
        this.startVolume = startVolume;
        this.endVolume = endVolume;

        this.yearMatchVolumeAc = getAccumulator(aggregateMatch, aggregateVolume);
    }

    @Override
    public boolean ignoreStatistics() {
        return false;
    }

    @Override
    public Accumulator getAccumulator() {
        return this.yearMatchVolumeAc;
    }

    private Accumulator getAccumulator(final Aggregate aggregateMatch,
            final Aggregate aggregateVolume) {

        return new Accumulator() {

            private StringBuilder b = new StringBuilder(100);
            private long matchSum, volumeSum;
            
            {
                reset();
            }

            @Override
            public void reset() {
                b.setLength(0);
                b.append("year\tmatch count\tvolume count\n");
                matchSum = 0;
                volumeSum = 0;
            }

            @Override
            public void accumulate(int year, long match, long volume) {

                if (MathExtended.bounded(year, startYear, endYear)) {

                    switch (aggregateMatch) {
                        case ALL:
                            matchSum += match;
                            break;

                        case EACH_YEAR:
                        default:
                            if (!MathExtended.bounded(match, startMatch, endMatch)) {
                                return;
                            }
                            break;
                    }

                    switch (aggregateVolume) {
                        case ALL:
                            volumeSum += volume;
                            break;

                        case EACH_YEAR:
                        default:
                            if (!MathExtended.bounded(volume, startVolume, endVolume)) {
                                return;
                            }
                            break;
                    }

                    b.append(year);
                    b.append('\t');
                    b.append(match);
                    b.append('\t');
                    b.append(volume);
                    b.append("\n");
                }

            }

            @Override
            public String getAccumulatedValue() {
                if (aggregateMatch == Aggregate.ALL) {
                    if (!MathExtended.bounded(matchSum, startMatch, endMatch)) {
                        return "";
                    } else {
                        b.append(" (Total_Match:");
                        b.append(matchSum);
                        b.append(")\n");
                    }
                }
                if (aggregateVolume == Aggregate.ALL) {
                    if (!MathExtended.bounded(volumeSum, startVolume, endVolume)) {
                        return "";
                    } else {
                        b.append(" (Total_Volume:");
                        b.append(volumeSum);
                        b.append(")\n");
                    }
                }

                return b.toString();
            }
        };
    }

    @Override
    public String toString() {
        return StringFunctions.concat(
                "Query: ", query,
                " Gram: [", Stringify.intToString(startGram), ",", Stringify.intToString(endGram), "]",
                " Year: [", Stringify.intToString(startYear), ",", Stringify.intToString(endYear), "]",
                " Match Count: [", Stringify.intToString(startMatch), ",", Stringify.intToString(endMatch), "]",
                " Volume Count: [", Stringify.intToString(startVolume), ",", Stringify.intToString(endVolume), "]");
    }
}
